/**
 * ReportGear(2011)
 */
package com.reportgear.report.model.auxiliary;

import java.util.ArrayList;
import java.util.List;

import com.reportgear.core.api.XmlSerializer;

/**
 * 抽象行列属性列表
 * 
 * @version 1.0 2011-3-12
 * @author <a herf="lexloo@gmail.com">lexloo</a>
 * @since Report 1.0
 * 
 */
public abstract class AbstractCRPropList<T extends AbstractCRProperty<T1>, T1 extends CRTypeInterface> implements
		Cloneable, XmlSerializer {
	/**
	 * UID
	 */
	private static final long serialVersionUID = 7769380879673365985L;

	private List<T> elements;
	/**
	 * 默认值
	 */
	private int defaultValue = 0;

	public AbstractCRPropList() {
		this.elements = new ArrayList<T>();
	}

	/**
	 * 构造函数
	 * 
	 * @param defaultValue
	 *            默认宽度
	 * @param size
	 *            大小
	 */
	public AbstractCRPropList(int defaultValue, int size) {
		this.elements = new ArrayList<T>(size);

		this.defaultValue = defaultValue;
		for (int i = 0; i < size; i++) {
			this.elements.add(createDefaultItem());
		}
	}

	/**
	 * 创建默认列
	 * 
	 * @return 默认列
	 */
	public abstract T createDefaultItem();

	/**
	 * 获取行列类型
	 * 
	 * @param index
	 *            索引
	 * @return 行列类型
	 */
	public abstract T1 getType(int index);

	/**
	 * 设置行列类型
	 * 
	 * @param index
	 *            索引
	 * @param type
	 *            行列类型
	 */
	public void setType(int index, T1 type) {
		this.checkSize(index);

		this.elements.get(index).setType(type);
	}

	/**
	 * 是否分组
	 * 
	 * @param index
	 *            索引
	 */
	public boolean isGroup(int index) {
		return this.elements.get(index).isGroup();
	}

	/**
	 * 设置行列分组
	 * 
	 * @param index
	 *            索引
	 * @param group
	 *            是否分组
	 */
	public void setGroup(int index, boolean group) {
		this.checkSize(index);

		this.elements.get(index).setGroup(group);
	}

	/**
	 * 获取行列类型显示名(短)
	 * 
	 * @param index
	 *            索引
	 * @return 行列类型
	 */
	public abstract String getTypeStringShort(int index);

	/**
	 * @return 获取默认值
	 */
	public int getDefaultValue() {
		return this.defaultValue;
	}

	/**
	 * 设置默认值
	 * 
	 * @param defaultValue
	 *            默认值
	 */
	// public void setDefaultValue(int defaultValue) {
	// this.defaultValue = defaultValue;
	// }

	/**
	 * 计算从0到toIndex之间所有值之和
	 * 
	 * @param toIndex
	 *            目标索引
	 * @return 和值
	 */
	public int getRangeValueFromZero(int toIndex) {
		return getRangeValue(0, toIndex);
	}

	/**
	 * 计算范围内所有值之和
	 * 
	 * @param fromIndex
	 *            开始索引
	 * @param toIndex
	 *            终止索引
	 * @return 和值
	 */
	public int getRangeValue(int fromIndex, int toIndex) {
		int result = 0;
		int index1 = Math.max(0, Math.min(fromIndex, toIndex));
		int index2 = Math.max(fromIndex, toIndex);

		while (index1 < index2) {
			result += this.getValue(index1);
			++index1;
		}

		return ((fromIndex <= toIndex) ? result : -result);
	}

	/**
	 * 获取达到指定和值时的索引
	 * 
	 * @param value
	 *            和值
	 * @return 索引
	 */
	public int getValueIndex(int value) {
		return getValueIndex(value, 0);
	}

	/**
	 * 获取达到指定和值时的索引
	 * 
	 * @param value
	 *            和值
	 * @param fromIndex
	 *            起始所有
	 * @return 索引
	 */
	public int getValueIndex(int value, int fromIndex) {
		int temp = 0;
		for (int index = fromIndex;; ++index) {
			temp += this.getValue(index);
			if (temp > value) {
				return index;
			}
		}
	}

	/**
	 * 获取指定索引属性的值
	 * 
	 * @param index
	 *            索引
	 * @return 值
	 */
	public int getValue(int index) {
		if (index >= this.elements.size()) {// 超过当前大小取默认值
			return this.defaultValue;
		} else {
			return this.elements.get(index).getValue();
		}
	}

	/**
	 * 设置指定索引的值
	 * 
	 * @param index
	 *            索引
	 * @param value
	 *            值
	 */
	public void setValue(int index, int value) {
		this.checkSize(index);

		this.elements.get(index).setValue(value);
	}

	/**
	 * 获取指定索引的值
	 * 
	 * @param index
	 *            索引
	 * @return 值
	 */
	public T get(int index) {
		return this.elements.get(index);
	}

	/**
	 * 获取所有元素列表
	 * 
	 * @return 所有元素列表
	 */
	public List<T> getAllElements() {
		return this.elements;
	}

	/**
	 * 清空列表
	 */
	public void clear() {
		this.elements.clear();
	}

	/**
	 * 增加对象到指定索引
	 * 
	 * @param index
	 *            索引
	 * @param element
	 *            对象
	 */
	public void add(int index, T element) {
		this.elements.add(index, element);
	}

	/**
	 * 增加对象
	 * 
	 * @param element
	 *            对象
	 */
	public void add(T element) {
		this.elements.add(element);
	}

	/**
	 * 移除指定索引的对象
	 * 
	 * @param index
	 *            索引
	 * @return 对象
	 */
	public T remove(int index) {
		return this.elements.remove(index);
	}

	/**
	 * 获取元素个数
	 * 
	 * @return 元素个数
	 */
	public int size() {
		return this.elements.size();
	}

	/**
	 * 是否可见
	 * 
	 * @param index
	 *            索引
	 * @return 是否可见
	 */
	public boolean isVisible(int index) {
		if (index >= this.elements.size()) {// 超过当前大小取默认值
			return true;
		} else {
			return this.elements.get(index).isVisible();
		}
	}

	/**
	 * 插入节点
	 * 
	 * @param fromIndex
	 *            开始Index
	 * @param prop
	 *            属性
	 */
	public void insert(int fromIndex, T prop) {
		insert(fromIndex, 1, prop);
	}

	/**
	 * 插入节点
	 * 
	 * @param fromIndex
	 *            起点
	 * @param length
	 *            长度
	 * @param prop
	 *            节点
	 */
	public void insert(int fromIndex, int length, T prop) {
		if ((fromIndex < 0) || (length <= 0)) {
			return;
		}

		for (int i = 0; i < length; i++) {
			this.elements.add(fromIndex + i, prop);
		}
	}

	/**
	 * 检查是否能够获取指定索引的值，如果不能则扩充
	 * 
	 * @param index
	 *            索引
	 */
	private void checkSize(int index) {
		if (index >= this.elements.size()) {// 索引超过当前大小扩充对象
			for (int i = 0, len = index - this.elements.size() + 1; i < len; i++) {
				this.elements.add(createDefaultItem());
			}
		}
	}

	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();
		for (T p : this.elements) {
			sb.append(",");
			sb.append(p.toString());
		}

		return sb.toString().substring(1);
	}

	/**
	 * 对象克隆
	 */
	public Object clone() {
		try {
			Object cloned = super.clone();

			return cloned;
		} catch (CloneNotSupportedException ex) {
			throw new InternalError();
		}
	}
}
